home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Telnet Server 1.0 / tcplow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-14  |  19.4 KB  |  786 lines  |  [TEXT/KAHL]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     tcplow.c
  4.  
  5.     This module all the low-level calls to MacTCP.
  6.     Copyright © Mikhail Fridberg, 1994
  7.     Portions copyright © 1990, Apple Computer.
  8.     Portions copyright © 1993, Northwestern University.
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <errno.h>
  15. #include <time.h>
  16. #include <stddef.h>
  17. #include <string.h>
  18. #include "MacSocket.h"
  19. #include <MacTCPCommonTypes.h>
  20. #include <TCPPB.h>
  21. #include <AddressXlation.h>
  22. #include <GetMyIPAddr.h>
  23. #include <MiscIPPB.h>
  24. #include "tcplow.h"
  25.  
  26.  
  27. Boolean     gCancel = false;            /* flag set when user cancels an action */
  28. short        gRefNum;
  29.  
  30.  
  31.  
  32. /*    This is the completion routine used for name-resolver calls.
  33.     It sets the userDataPtr flag to indicate the call has completed.
  34. */
  35.  
  36. pascal void DNRResultProc(struct hostInfo *hInfoPtr,char *userDataPtr)
  37. {
  38. #pragma unused (hInfoPtr)
  39.  
  40.     *userDataPtr = 0xff;    /* setting the use data to non-zero means we're done */
  41. }
  42.  
  43.  
  44. short GetTCPRefNum (void)
  45. {
  46.     return gRefNum;
  47. }
  48.  
  49.  
  50. static void InitBlock (TCPiopb *pBlock)
  51. {
  52.     memset(pBlock, 0L, sizeof(TCPiopb));
  53.     pBlock->ioResult = 1;
  54.     pBlock->ioCRefNum = GetTCPRefNum();
  55. }
  56.  
  57.  
  58. static OSErr NewBlock (TCPiopb **pBlock)
  59. {
  60.     *pBlock = (TCPiopb *)malloc(sizeof(TCPiopb));
  61.     if (MemError() != noErr) {
  62.         printf ("Couldn not allocate memory, error = %d\n", MemError());
  63.         return MemError();
  64.     }
  65.     (*pBlock)->ioCompletion = 0L;
  66.     (*pBlock)->ioCRefNum = gRefNum;
  67.     return noErr;
  68. }
  69.  
  70.  
  71. /* Opens the MacTCP driver.
  72.    This routine must be called prior to any of the below functions. */
  73.  
  74. OSErr OpenTCPDriver (void)
  75. {
  76.     OSErr    err;
  77.     
  78.     err = OpenDriver("\p.IPP", &gRefNum);
  79.     return(err);
  80. }
  81.  
  82.  
  83. /* Creates a new TCP stream in preparation for initiating a connection.
  84.    A buffer must be provided for storing incoming data waiting to be processed */
  85.  
  86. OSErr LowTCPCreateStream (StreamPtr *streamPtr, Ptr connectionBuffer,
  87.     unsigned long connBufferLen, TCPNotifyProc notifPtr)
  88. {
  89.     OSErr err;
  90.     TCPiopb *pBlock = 0;
  91.     
  92.     if ((err = NewBlock(&pBlock)) != noErr)
  93.         return err;
  94.         
  95.     pBlock->csCode = TCPCreate;
  96.     pBlock->ioResult = 1;
  97.     pBlock->csParam.create.rcvBuff = connectionBuffer;
  98.     pBlock->csParam.create.rcvBuffLen = connBufferLen;
  99.     pBlock->csParam.create.notifyProc = notifPtr;
  100.     PBControl((ParmBlkPtr)pBlock,true);
  101.     while (pBlock->ioResult > 0 && GiveTime())
  102.         ;
  103.     if (gCancel)
  104.         return -1;
  105.         
  106.     *streamPtr = pBlock->tcpStream;
  107.     err = pBlock->ioResult;
  108.     free((Ptr)pBlock);
  109.         if (MemError() != noErr) {
  110.         printf ("Couldn not free memory, error = %d\n", MemError());
  111.         }
  112.     return err;
  113.  
  114. }
  115.  
  116.  
  117. /* If TCPWaitForConnection is called asynchronously, this command retrieves the 
  118.    result of the call.  It should be called when the above command completes. */
  119.  
  120. OSErr LowFinishTCPWaitForConn (TCPiopb *pBlock, ip_addr *remoteHost,
  121.     tcp_port *remotePort, ip_addr *localHost, tcp_port *localPort)
  122. {    
  123.     OSErr err;
  124.     
  125.     *remoteHost = pBlock->csParam.open.remoteHost;
  126.     *remotePort = pBlock->csParam.open.remotePort;
  127.     *localHost = pBlock->csParam.open.localHost;
  128.     *localPort = pBlock->csParam.open.localPort;
  129.     err = pBlock->ioResult;
  130.     free((Ptr)pBlock);
  131.      if (MemError() != noErr) {
  132.         printf ("Couldn not free memory, error = %d\n", MemError());
  133.         }
  134.     return err;
  135. }
  136.  
  137.  
  138. /* Waits for a connection to be opened on a specified port from a specified address.
  139.    It completes when a connection is made, or a timeout value is reached.  This call
  140.    may be made asynchronously. */
  141.  
  142. OSErr LowTCPWaitForConnection (StreamPtr streamPtr, byte timeout,
  143.     ip_addr *remoteHost, tcp_port *remotePort, ip_addr *localHost,
  144.     tcp_port *localPort, Boolean async, TCPiopb **returnBlock)
  145. {
  146.     OSErr err;
  147.     TCPiopb *pBlock = 0;
  148.     
  149.     if ((err = NewBlock(&pBlock)) != noErr)
  150.         return err;
  151.     
  152.     pBlock->csCode = TCPPassiveOpen;
  153.     pBlock->ioResult = 1;
  154.     pBlock->ioCompletion = nil;
  155.     pBlock->tcpStream = streamPtr;
  156.     pBlock->csParam.open.ulpTimeoutValue = timeout;
  157.     pBlock->csParam.open.ulpTimeoutAction = 1;
  158.     pBlock->csParam.open.validityFlags = 0xC0;
  159.     pBlock->csParam.open.commandTimeoutValue = timeout;
  160.     pBlock->csParam.open.remoteHost = *remoteHost;
  161.     pBlock->csParam.open.remotePort = *remotePort;
  162.     pBlock->csParam.open.localPort = *localPort;
  163.     pBlock->csParam.open.tosFlags = 0;
  164.     pBlock->csParam.open.precedence = 0;
  165.     pBlock->csParam.open.dontFrag = 0;
  166.     pBlock->csParam.open.timeToLive = 0;
  167.     pBlock->csParam.open.security = 0;
  168.     pBlock->csParam.open.optionCnt = 0;
  169.     PBControl((ParmBlkPtr)pBlock,true);
  170.     if (!async) {
  171.         while (pBlock->ioResult > 0 && GiveTime())
  172.             ;
  173.         err = gCancel ? -1 : pBlock->ioResult;
  174.         if (gCancel) LowTCPAbort(streamPtr);
  175.         LowFinishTCPWaitForConn(pBlock,remoteHost,remotePort,localHost,localPort);
  176.         return err;
  177.     }
  178.     
  179.     *returnBlock = pBlock;
  180.     return noErr;
  181. }
  182.  
  183.  
  184. /* Attempts to initiate a connection with a host specified by host and port. */
  185.  
  186. OSErr LowTCPOpenConnection (StreamPtr streamPtr, Byte timeout, 
  187.     ip_addr remoteHost, tcp_port remotePort, ip_addr *localHost,
  188.     tcp_port *localPort)
  189. {
  190.     OSErr err;
  191.     TCPiopb *pBlock = 0;
  192.  
  193.     
  194.     if ((err = NewBlock(&pBlock)) != noErr)
  195.         return err;
  196.     
  197.     pBlock->csCode = TCPActiveOpen;
  198.     pBlock->ioResult = 1;
  199.     pBlock->tcpStream = streamPtr;
  200.     pBlock->csParam.open.ulpTimeoutValue = timeout;
  201.     pBlock->csParam.open.ulpTimeoutAction = 1;
  202.     pBlock->csParam.open.validityFlags = 0xC0;
  203.     pBlock->csParam.open.commandTimeoutValue = timeout;
  204.     pBlock->csParam.open.remoteHost = remoteHost;
  205.     pBlock->csParam.open.remotePort = remotePort;
  206.     pBlock->csParam.open.localPort = *localPort;
  207.     pBlock->csParam.open.tosFlags = 0;
  208.     pBlock->csParam.open.precedence = 0;
  209.     pBlock->csParam.open.dontFrag = 0;
  210.     pBlock->csParam.open.timeToLive = 0;
  211.     pBlock->csParam.open.security = 0;
  212.     pBlock->csParam.open.optionCnt = 0;
  213.     PBControl((ParmBlkPtr)pBlock,true);
  214.     while (pBlock->ioResult > 0 && GiveTime())
  215.         ;
  216.     if (gCancel)
  217.         return -1;
  218.     *localHost = pBlock->csParam.open.localHost;
  219.     *localPort = pBlock->csParam.open.localPort;
  220.     err = pBlock->ioResult;
  221.     free((Ptr)pBlock);
  222.     if (MemError() != noErr) {
  223.         printf ("Couldn not free memory, error = %d\n", MemError());
  224.         }
  225.     return err;
  226. }
  227.  
  228.  
  229. /* This routine should be called when a TCPSendData call completes.  It returns the
  230.    error code generated upon completion of the CallTCPSend. */
  231.  
  232. OSErr LowFinishTCPSend (TCPiopb *pBlock)
  233. {
  234.     OSErr err;
  235.     
  236.     err = pBlock->ioResult;
  237.     free((Ptr)pBlock);
  238.     if (MemError() != noErr) {
  239.         printf ("Couldn not free memory, error = %d\n", MemError());
  240.         }
  241.     return err;
  242. }
  243.  
  244.  
  245. /* Sends data through an open connection stream.  Note that the connection must be
  246.    open before any data is sent. This call may be made asynchronously. */
  247.  
  248. OSErr LowTCPSendData (StreamPtr streamPtr, byte timeout, Boolean push,
  249.     Boolean urgent, Ptr wdsPtr, Boolean async, TCPiopb **returnBlock)
  250. {    
  251.     OSErr err;
  252.     TCPiopb *pBlock = 0;
  253.     
  254.     if ((err = NewBlock(&pBlock)) != noErr)
  255.         return err;
  256.     
  257.     pBlock->csCode = TCPSend;
  258.     pBlock->ioResult = 1;
  259.     pBlock->tcpStream = streamPtr;
  260.     pBlock->ioCompletion = nil;
  261.     pBlock->csParam.send.ulpTimeoutValue = timeout;
  262.     pBlock->csParam.send.ulpTimeoutAction = 1;
  263.     pBlock->csParam.send.validityFlags = 0xC0;
  264.     pBlock->csParam.send.pushFlag = push;
  265.     pBlock->csParam.send.urgentFlag = urgent;
  266.     pBlock->csParam.send.wdsPtr = wdsPtr;
  267.     PBControl((ParmBlkPtr)pBlock,true);
  268.     if (!async) {
  269.         while (pBlock->ioResult > 0 && GiveTime())
  270.             ;
  271.         err = gCancel ? -1 : pBlock->ioResult;
  272.         if (gCancel) LowTCPAbort(streamPtr);
  273.         LowFinishTCPSend(pBlock);
  274.         return err;
  275.     }
  276.     
  277.     *returnBlock = pBlock;
  278.     return noErr;
  279. }
  280.  
  281.  
  282. OSErr LowFinishTCPNoCopyRcv (TCPiopb *pBlock, Boolean *urgent, Boolean *mark)
  283. {
  284.     OSErr err;
  285.     
  286.     *urgent = pBlock->csParam.receive.urgentFlag;
  287.     *mark = pBlock->csParam.receive.markFlag;
  288.     
  289.     err = pBlock->ioResult;
  290.     free((Ptr)pBlock);
  291.     if (MemError() != noErr) {
  292.         printf ("Couldn not free memory, error = %d\n", MemError());
  293.         }
  294.     return err;
  295. }
  296.  
  297.  
  298. OSErr LowTCPNoCopyRcv (StreamPtr streamPtr, byte timeout, Boolean *urgent,
  299.     Boolean *mark, Ptr rdsPtr, short numEntry, Boolean async,
  300.     TCPiopb **returnBlock)
  301. {
  302.     OSErr    err = noErr;
  303.     TCPiopb *pBlock = 0;
  304.     
  305.     if ((err = NewBlock(&pBlock)) != noErr)
  306.         return err;
  307.     
  308.     pBlock->csCode = TCPNoCopyRcv;
  309.     pBlock->tcpStream = streamPtr;
  310.     pBlock->ioResult = 1;
  311.     pBlock->ioCompletion = nil;
  312.     pBlock->csParam.receive.commandTimeoutValue = timeout;
  313.     pBlock->csParam.receive.rdsPtr = rdsPtr;
  314.     pBlock->csParam.receive.rdsLength = numEntry;
  315.     PBControl((ParmBlkPtr)pBlock,true);
  316.     if (!async) {
  317.         while (pBlock->ioResult > 0 && GiveTime())
  318.             ;
  319.         err = gCancel ? -1 : pBlock->ioResult;
  320.         if (gCancel) LowTCPAbort(streamPtr);
  321.         LowFinishTCPNoCopyRcv(pBlock,urgent,mark);
  322.         return err;
  323.     }
  324.     
  325.     *returnBlock = pBlock;
  326.     return noErr;
  327. }
  328.  
  329.  
  330. OSErr LowTCPBfrReturn (StreamPtr streamPtr, Ptr rdsPtr)
  331. {
  332.     OSErr err;
  333.     TCPiopb *pBlock = 0;
  334.     
  335.     if ((err = NewBlock(&pBlock)) != noErr)
  336.         return err;
  337.     
  338.     pBlock->csCode = TCPRcvBfrReturn;
  339.     pBlock->ioResult = 1;
  340.     pBlock->tcpStream = streamPtr;
  341.     pBlock->csParam.receive.rdsPtr = rdsPtr;
  342.     PBControl((ParmBlkPtr)pBlock,true);
  343.     while (pBlock->ioResult > 0 && GiveTime())
  344.         ;
  345.     if (gCancel)
  346.         return -1;
  347.     err = pBlock->ioResult;
  348.     free((Ptr)pBlock);
  349.     if (MemError() != noErr) {
  350.         printf ("Couldn not free memory, error = %d\n", MemError());
  351.         }
  352.     return err;
  353. }
  354.  
  355.  
  356. /* If the above is called asynchronously, this routine returns the data that was
  357.    received from the remote host. */
  358.    
  359. OSErr LowFinishTCPRecv (TCPiopb *pBlock, Boolean *urgent, Boolean *mark,
  360.     unsigned short *rcvLen)
  361. {
  362.     OSErr err;
  363.     
  364.     *rcvLen = pBlock->csParam.receive.rcvBuffLen;
  365.     *urgent = pBlock->csParam.receive.urgentFlag;
  366.     *mark = pBlock->csParam.receive.markFlag;
  367.     err = pBlock->ioResult;
  368.     free((Ptr)pBlock);
  369.     if (MemError() != noErr) {
  370.         printf ("Couldn not free memory, error = %d\n", MemError());
  371.         }
  372.     return err;
  373. }
  374.  
  375.  
  376. /* Attempts to pull data out of the incoming stream for a connection. If data is
  377.    not present, the routine waits a specified amout of time before returning with
  378.    a timeout error.  This call may be made asynchronously. */
  379.    
  380. OSErr LowTCPRecvData (StreamPtr streamPtr, byte timeout, Boolean *urgent,
  381.     Boolean *mark, Ptr rcvBuff, unsigned short *rcvLen, Boolean async,
  382.     TCPiopb **returnBlock)
  383. {
  384.     OSErr         err;
  385.     TCPiopb     *pBlock = 0;
  386.  
  387.     
  388.     if ((err = NewBlock(&pBlock)) != noErr)
  389.         return err;
  390.     
  391.     pBlock->csCode = TCPRcv;
  392.     pBlock->ioResult = 1;
  393.     pBlock->ioCompletion = nil;
  394.     pBlock->tcpStream = streamPtr;
  395.     pBlock->csParam.receive.commandTimeoutValue = timeout;
  396.     pBlock->csParam.receive.rcvBuff = rcvBuff;
  397.     pBlock->csParam.receive.rcvBuffLen = *rcvLen;
  398.     PBControl((ParmBlkPtr)pBlock,true);
  399.     if (!async) {
  400.         while (pBlock->ioResult > 0 && GiveTime())
  401.             ;
  402.         err = gCancel ? -1 : pBlock->ioResult;
  403.         if (gCancel) LowTCPAbort(streamPtr);
  404.         LowFinishTCPRecv(pBlock,urgent,mark,rcvLen);
  405.         return err;
  406.         }
  407.     
  408.  
  409.     *returnBlock = pBlock;
  410.     return noErr;
  411. }
  412.     
  413.  
  414. /* Gracefully closes a connection with a remote host.  This is not always possible,
  415.    and the programmer might have to resort to CallTCPAbort, described next. */
  416.  
  417. OSErr LowTCPClose (StreamPtr streamPtr, byte timeout)
  418. {
  419.     OSErr err;
  420.     TCPiopb *pBlock = 0;
  421.     
  422.     if ((err = NewBlock(&pBlock)) != noErr)
  423.         return err;
  424.     
  425.     pBlock->csCode = TCPClose;
  426.     pBlock->ioResult = 1;
  427.     pBlock->tcpStream = streamPtr;
  428.     pBlock->csParam.close.ulpTimeoutValue = timeout;
  429.     pBlock->csParam.close.validityFlags = 0xC0;
  430.     pBlock->csParam.close.ulpTimeoutAction = 1;
  431.     PBControl((ParmBlkPtr)&pBlock,true);
  432.     while (pBlock->ioResult > 0 && GiveTime())
  433.         ;
  434.     err = gCancel ? -1 : pBlock->ioResult;
  435.     if (gCancel) LowTCPAbort(streamPtr);
  436.     free((Ptr)pBlock);
  437.     if (MemError() != noErr) {
  438.         printf ("Couldn not free memory, error = %d\n", MemError());
  439.         }
  440.  
  441.     return err;
  442. }
  443.  
  444.  
  445. /* Should be called if a CallTCPClose fails to close a connection properly.
  446.    This call should not normally be used to terminate connections. */
  447.    
  448. OSErr LowTCPAbort (StreamPtr streamPtr)
  449. {
  450.     OSErr err;
  451.     TCPiopb *pBlock = 0;
  452.     
  453.     if ((err = NewBlock(&pBlock)) != noErr)
  454.         return err;
  455.     
  456.     pBlock->csCode = TCPAbort;
  457.     pBlock->ioResult = 1;
  458.     pBlock->tcpStream = streamPtr;
  459.     PBControl((ParmBlkPtr)pBlock,true);
  460.     while (pBlock->ioResult > 0 && GiveTime())
  461.         ;
  462.     if (gCancel)
  463.         return -1;
  464.     err = pBlock->ioResult;
  465.     free((Ptr)pBlock);
  466.     if (MemError() != noErr) {
  467.         printf ("Couldn not free memory, error = %d\n", MemError());
  468.         }
  469.     return err;
  470. }
  471.  
  472. OSErr LowTCPStatus (StreamPtr streamPtr, TCPStatusPB *theStatus)
  473. {
  474.     OSErr err;
  475.     TCPiopb *pBlock = 0;
  476.     
  477.     if ((err = NewBlock(&pBlock)) != noErr)
  478.         return err;
  479.     
  480.     pBlock->csCode = TCPStatus;
  481.     pBlock->ioResult = 1;
  482.     pBlock->tcpStream = streamPtr;
  483.     PBControl((ParmBlkPtr)pBlock,true);
  484.     while (pBlock->ioResult > 0 && GiveTime())
  485.         ;
  486.     if (gCancel)
  487.         return -1;
  488.     theStatus = &(pBlock->csParam.status);
  489.     err = pBlock->ioResult;
  490.     free((Ptr)pBlock);
  491.     if (MemError() != noErr) {
  492.         printf ("Couldn not free memory, error = %d\n", MemError());
  493.         }
  494.     return err;
  495. }
  496.  
  497.  
  498. /* Deallocates internal buffers used to hold connection data. This should be
  499.    called after a connection has been closed. */
  500.  
  501. OSErr LowTCPRelease (StreamPtr streamPtr, Ptr *recvPtr, unsigned long *recvLen)
  502. {
  503.     OSErr err;
  504.     TCPiopb *pBlock = 0;
  505.     
  506.     if ((err = NewBlock(&pBlock)) != noErr)
  507.         return err;
  508.     
  509.     pBlock->csCode = TCPRelease;
  510.     pBlock->ioResult = 1;
  511.     pBlock->tcpStream = streamPtr;
  512.     PBControl((ParmBlkPtr)pBlock,true);
  513.     while (pBlock->ioResult > 0 && GiveTime())
  514.         ;
  515.     if (gCancel)
  516.         return -1;
  517.     *recvPtr = pBlock->csParam.create.rcvBuff;
  518.     *recvLen = pBlock->csParam.create.rcvBuffLen;
  519.     err = pBlock->ioResult;
  520.     free((Ptr)pBlock);
  521.     if (MemError() != noErr) {
  522.         printf ("Couldn not free memory, error = %d\n", MemError());
  523.         }
  524.     return err;
  525. }
  526.  
  527. OSErr LowTCPGlobalInfo (Ptr *tcpParam, Ptr *tcpStat)
  528. {
  529.     OSErr err;
  530.     TCPiopb *pBlock = 0;
  531.     
  532.     if ((err = NewBlock(&pBlock)) != noErr)
  533.         return err;
  534.     
  535.     pBlock->csCode = TCPGlobalInfo;
  536.     pBlock->ioResult = 1;
  537.     PBControl((ParmBlkPtr)pBlock,true);
  538.     while (pBlock->ioResult > 0 && GiveTime())
  539.         ;
  540.     if (gCancel)
  541.         return -1;
  542.     *tcpParam = (Ptr) pBlock->csParam.globalInfo.tcpParamPtr;
  543.     *tcpStat = (Ptr) pBlock->csParam.globalInfo.tcpStatsPtr;
  544.     err = pBlock->ioResult;
  545.     free((Ptr)pBlock);
  546.     if (MemError() != noErr) {
  547.         printf ("Couldn not free memory, error = %d\n", MemError());
  548.         }
  549.     return err;
  550. }
  551.  
  552.  
  553.  
  554. /*    LowIPNameToAddr invokes the domain name system to translate a domain name
  555.     into an IP address. */
  556.     
  557. OSErr LowIPNameToAddr (char *name, unsigned long *addr)
  558. {
  559.     struct hostInfo hInfo;
  560.     OSErr err;
  561.     Boolean done=false;
  562.     
  563.     if ((err = OpenResolver(nil)) != noErr) return err;
  564.     err = StrToAddr(name, &hInfo, DNRResultProc, (char*)&done);
  565.     if (err == cacheFault) {
  566.         while (!done) GiveTime();
  567.         err = hInfo.rtnCode;
  568.     }
  569.     CloseResolver();
  570.     *addr = hInfo.addr[0];
  571.     return gCancel ? -1 : err;
  572. }
  573.  
  574.  
  575. /*    LowIPAddrToName invokes the domain name system to translate an IP address
  576.     into a domain name. */
  577.  
  578. OSErr LowIPAddrToName (unsigned long addr, char *name)
  579. {
  580.     struct hostInfo hInfo;
  581.     OSErr err;
  582.     Boolean done=false;
  583.     
  584.     if ((err = OpenResolver(nil)) != noErr) return err;
  585.     err = AddrToName(addr, &hInfo, DNRResultProc, (char*)&done);
  586.     if (err == cacheFault) {
  587.         while (!done) GiveTime();
  588.         err = hInfo.rtnCode;
  589.     }
  590.     CloseResolver();
  591.     hInfo.cname[254] = 0;
  592.     strcpy(name,hInfo.cname);
  593.     return gCancel ? -1 : err;
  594. }
  595.  
  596.  
  597. /* LowGetMyIPAddr returns the IP address of this Mac. */
  598.  
  599. OSErr LowGetMyIPAddr (unsigned long *addr)
  600. {
  601.     struct    GetAddrParamBlock    IPBlock;
  602.     
  603.     memset(&IPBlock, 0, sizeof(IPBlock));
  604.     IPBlock.ioResult = 1;
  605.     IPBlock.csCode = ipctlGetAddr;
  606.     IPBlock.ioCRefNum = gRefNum;
  607.     PBControl((ParmBlkPtr)&IPBlock,true);
  608.     while (IPBlock.ioResult > 0) GiveTime();
  609.  
  610.  
  611.     *addr = IPBlock.ourAddress;
  612.     
  613.     
  614.     return gCancel ? -1 : IPBlock.ioResult;
  615. }
  616.  
  617.  
  618. /*    LowGetMyIPAddrStr returns the IP address of this Mac as a dotted decimal
  619.     string. */
  620.     
  621. OSErr LowGetMyIPAddrStr (char *addrStr)
  622. {
  623.     unsigned long addr;
  624.     OSErr err;
  625.     static char theAddrStr[16];
  626.     static Boolean gotIt=false;
  627.     
  628.     if (!gotIt) {
  629.         if ((err = LowGetMyIPAddr(&addr)) != noErr) return err;
  630.         if ((err = OpenResolver(nil)) != noErr) return err;
  631.         err = AddrToStr(addr,theAddrStr);
  632.         CloseResolver();
  633.         if (err != noErr) return err;
  634.         gotIt = true;
  635.     }
  636.     strcpy(addrStr,theAddrStr);
  637.     return noErr;
  638. }
  639. OSErr GetMyIP(ip_addr *ipnum)
  640. {
  641.     struct    GetAddrParamBlock    *IPBlock = 0;
  642.     OSErr    err;
  643.     
  644.     IPBlock = (struct GetAddrParamBlock *)malloc(sizeof(struct GetAddrParamBlock));
  645.     if (MemError() != noErr) {
  646.         printf ("Couldn not allocate memory, error = %d\n", MemError());
  647.         return MemError();
  648.     }
  649.     IPBlock->ioResult = 1;
  650.     IPBlock->csCode = ipctlGetAddr;
  651.     IPBlock->ioCompletion = nil;
  652.     IPBlock->ioCRefNum = gRefNum;
  653.     PBControl((ParmBlkPtr)IPBlock,true);
  654.     while (IPBlock->ioResult > 0 && GiveTime())
  655.         ;
  656.     if (gCancel)
  657.         return -1;
  658.     *ipnum = IPBlock->ourAddress;
  659.     err = IPBlock->ioResult;
  660.     free((Ptr)IPBlock);
  661.     if (MemError() != noErr) {
  662.         printf ("Couldn not allocate memory, error = %d\n", MemError());
  663.         }
  664.     return err;
  665. }
  666.  
  667. /* RecvData() waits for data to be received on a connection stream.  When data
  668.    arrives, it is copied into the data buffer and the call terminates. */
  669.  
  670. OSErr RecvData (unsigned long stream, Ptr data, unsigned short *length,
  671.     Boolean retry)
  672. {
  673.     Boolean    urgent,mark;
  674.     OSErr    err;
  675.     unsigned short recvLength;
  676.  
  677.     do {
  678.         recvLength = *length;
  679.         err = LowTCPRecvData(stream,1,&urgent,&mark,data,&recvLength,false,nil);
  680.     }
  681.     while (retry && err==commandTimeout);
  682.     *length = recvLength;
  683.     if (err == noErr) *(data+*length) = 0;
  684.     return err;
  685. }
  686.  
  687. /* SendData() sends data along a connection stream to a remote host. */
  688.  
  689. OSErr SendData (unsigned long stream, Ptr data, unsigned short length)
  690. {    
  691.     struct wdsEntry myWDS[2];    /* global write data structure */
  692.  
  693.     myWDS[0].length = length;
  694.     myWDS[0].ptr = data;
  695.     myWDS[1].length = 0;
  696.     myWDS[1].ptr = nil;
  697.     return LowTCPSendData(stream,120,false,false,(Ptr) myWDS,false,nil);
  698. }
  699.  
  700. /*************************************************************************************/
  701. /*            This are utilities routines                                            */
  702. /*************************************************************************************/
  703.  
  704.  
  705.  
  706. /*    GiveTime is called whenever the application is waiting for a slow
  707.     process to complete.  The routine calls SpinCursor and WaitNextEvent
  708.     to give time to currently running background applications.
  709. */
  710.  
  711. Boolean GiveTime (void)
  712. {
  713.     EventRecord ev;
  714.     Boolean gotEvt;
  715.  
  716.             
  717.     SpinCursor(1);
  718.     gotEvt = WaitNextEvent(everyEvent,&ev,0x01,nil);
  719.     return !gCancel;
  720. }
  721.  
  722.  
  723. /*    pstrcpy copies Pascal format strings.
  724. */
  725.  
  726. void pstrcpy (StringPtr to, StringPtr from)
  727. {
  728.     BlockMove(from, to, *from+1);
  729. }
  730.  
  731.  
  732.  
  733.  
  734. /*    The InitCursorCtl, SpinCursor functions 
  735.     are missing in Think, so we include them here    */
  736.  
  737. Handle gAcur = nil;
  738.  
  739. pascal void InitCursorCtl (Handle id)
  740. {
  741.     short NoFrames, i, CursId;
  742.     CursHandle    TheCursHndl;
  743.  
  744.     if (id == nil) {
  745.         gAcur = (Handle) GetResource('acur',0);
  746.         if(gAcur == nil) return;
  747.         HLock(gAcur);
  748.         NoFrames = ((short *)(*gAcur))[0];
  749.         for(i = 0; i < NoFrames; i++) {
  750.             CursId = ((short *)(*gAcur))[(2*i)+2];
  751.             TheCursHndl = GetCursor(CursId);
  752.             ((CursHandle *)(*gAcur))[i+1] = TheCursHndl;
  753.             HLock((Handle)TheCursHndl);
  754.         }
  755.     } else {
  756.         gAcur = id;
  757.         HLock(gAcur);
  758.         NoFrames = ((short *)(*gAcur))[0];
  759.         for(i = 0; i < NoFrames; i++) {
  760.             CursId = ((short *)(*gAcur))[(2*i)+2];
  761.             TheCursHndl = GetCursor(CursId);
  762.             ((CursHandle *)(*gAcur))[i+1] = TheCursHndl;
  763.             HLock((Handle)TheCursHndl);
  764.         }
  765.     }
  766.     ((short *)(*gAcur))[1] = 0;
  767.     DetachResource(gAcur);
  768. }
  769.  
  770.  
  771. pascal void SpinCursor (short num)
  772. {
  773.     short    NoFrames, CurrentFrame, CurrentCounter;
  774.     Cursor    CurrentCursor;
  775.  
  776.     if (gAcur == nil) InitCursorCtl(nil);
  777.     NoFrames = ((short *)(*gAcur))[0];
  778.     CurrentCounter = ((((short *)(*gAcur))[1] + num) % (NoFrames * 32));
  779.     ((short *)(*gAcur))[1] = CurrentCounter;
  780.     CurrentFrame = CurrentCounter / 32;
  781.     CurrentCursor = **(((CursHandle *)(*gAcur))[CurrentFrame+1]);
  782.     SetCursor(&CurrentCursor);
  783. }
  784.  
  785.  
  786.